package com.muyu.danmo.service.impl;



import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.muyu.danmo.domain.dto.PersonBaseInfoDTO;
import com.muyu.danmo.domain.es.PersonInfoEs;
import com.muyu.danmo.domain.mapstruct.PersonMapper;
import com.muyu.danmo.domain.vo.PersonBaseInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.metrics.TopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author Administrator
 */
@Service
@Slf4j
public class AggregationService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private PersonMapper  personMapper;


    /**
     * 获取市主页
     * @param personBaseInfoDTO
     * @return
     */
    public List<?> findCity(PersonBaseInfoDTO personBaseInfoDTO) throws IOException {
        SearchRequest searchRequest = new SearchRequest("v_danmo_person_info_all");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(personBaseInfoDTO);

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.aggregation(
                AggregationBuilders.terms("by_entry_first_letter")
                        .field("entryFirstLetter.keyword")
                        .order(BucketOrder.key(true))
                        .size(1000)
                        .subAggregation(
                                AggregationBuilders.terms("by_address_entry")
                                        .field("addressEntry.keyword")
                                        .size(1000)
                                        .subAggregation(
                                                AggregationBuilders.terms("by_address_city")
                                                        .field("addressCity.keyword")
                                                        .size(1000)
                                                        .subAggregation(
                                                                AggregationBuilders.topHits("top_hits")
                                                                        .size(4)
                                                        )
                                        )
                        )
        );
        searchRequest.source(sourceBuilder);
        // 执行查询
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        log.info("es 查询打印：{}",sourceBuilder.toString());
        // 解析聚合结果
        Aggregations aggregations = searchResponse.getAggregations();
        Terms firstLetterAgg = aggregations.get("by_entry_first_letter");
        List<Map<String,Object>> list = new ArrayList<>();
        for (Bucket firstLetterBucket : firstLetterAgg.getBuckets()) {
            String firstLetter = firstLetterBucket.getKeyAsString();
            Map<String, Object> map = new HashMap<>();
            map.put("firstLetter",firstLetter);
            Terms addressEntryAgg = firstLetterBucket.getAggregations().get("by_address_entry");
            List<Map> objects = new ArrayList<>();
            for (Bucket addressEntryBucket : addressEntryAgg.getBuckets()) {
                Map<String, Object>  objectMap= new HashMap<>();
                String addressEntry = addressEntryBucket.getKeyAsString();
                // 每个省的总数据条数
                long total = addressEntryBucket.getDocCount();
                objectMap.put("province",addressEntry);
                objectMap.put("people",total);
                List<Object> cities = new ArrayList<>();
                Terms addressCityAgg = addressEntryBucket.getAggregations().get("by_address_city");
                for (Bucket addressCityBucket : addressCityAgg.getBuckets()) {
                    String addressCity = addressCityBucket.getKeyAsString();
                    // 每个市的总数据条数
                    long totalCity = addressCityBucket.getDocCount();
                    Map<String, Object>  cityMap= new HashMap<>();
                    cityMap.put("city",addressCity);
                    cityMap.put("people",totalCity);
                    TopHits topHits = addressCityBucket.getAggregations().get("top_hits");
                    List<PersonBaseInfoVO> personBaseInfo = new ArrayList<>();
                    topHits.getHits().forEach(hit -> {
                        Map<String, Object> source = hit.getSourceAsMap();
                        PersonInfoEs bean = BeanUtil.toBean(source, PersonInfoEs.class);
                        PersonBaseInfoVO personBaseInfoVO = personMapper.to(bean);
                        personBaseInfoVO.setId(Long.valueOf(bean.getPersonId()));
                        personBaseInfo.add(personBaseInfoVO);
                    });
                    cityMap.put("list",personBaseInfo);
                    cities.add(cityMap);
                }
                objectMap.put("cities",cities);
                objects.add(objectMap);
            }
            map.put("list",objects);
            list.add(map);
        }
        return list;
    }


    /**
     * 获取省详情会员信息
     * @param personBaseInfoDTO
     * @return
     */
    public Map<String,Object> findDetailMember(PersonBaseInfoDTO personBaseInfoDTO) throws IOException {
        SearchRequest searchRequest = new SearchRequest("v_danmo_person_info_all");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(personBaseInfoDTO);
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.aggregation(
                AggregationBuilders.terms("by_first_letter")
                        .field("firstLetter.keyword")
                        .order(BucketOrder.key(true))
                        .size(3000)
                        .subAggregation(
                                AggregationBuilders.topHits("top_hits")
                                        .size(2000)
                        )
        );
        searchRequest.source(sourceBuilder);
        // 执行查询
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        // 解析聚合结果
        Aggregations aggregations = searchResponse.getAggregations();
        Terms firstLetterAgg = aggregations.get("by_first_letter");
        HashMap<String, Object> resp = new HashMap<>();
        resp.put("province",personBaseInfoDTO.getAddressEntry());
        List<Map<String,Object>> list = new ArrayList<>();
        Long count = 0L;
        for (Bucket firstLetterBucket : firstLetterAgg.getBuckets()) {
            Map<String, Object> map = new HashMap<>();
            String firstLetter = firstLetterBucket.getKeyAsString();
            count = count + firstLetterBucket.getDocCount();
            TopHits topHits = firstLetterBucket.getAggregations().get("top_hits");

            List<PersonBaseInfoVO> personBaseInfo = new ArrayList<>();
            topHits.getHits().forEach(hit -> {
                Map<String, Object> source = hit.getSourceAsMap();
                PersonInfoEs bean = BeanUtil.toBean(source, PersonInfoEs.class);
                PersonBaseInfoVO personBaseInfoVO = personMapper.to(bean);
                personBaseInfoVO.setId(Long.valueOf(bean.getPersonId()));
                personBaseInfo.add(personBaseInfoVO);
            });
            map.put(firstLetter,personBaseInfo);
            list.add(map);
        }
        resp.put("list",list);
        resp.put("people",count);
        return resp;
    }
    /**
     * es聚合数据
     * @param personBaseInfoDTO
     * @return
     * @throws IOException
     */
    public List<?> performAggregationQuery(PersonBaseInfoDTO personBaseInfoDTO) throws IOException {

        SearchRequest searchRequest = new SearchRequest("v_danmo_person_info_all");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(personBaseInfoDTO);

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.aggregation(
                AggregationBuilders.terms("by_entry_first_letter")
                        .field("entryFirstLetter.keyword")
                        .order(BucketOrder.key(true))
                        .size(1000)
                        .subAggregation(
                                AggregationBuilders.terms("by_address_entry")
                                        .field("addressEntry.keyword")
                                        .size(1000)
                                        .subAggregation(
                                                AggregationBuilders.topHits("top_hits")
                                                        .size(4)
                                        )
                        )
        );
        searchRequest.source(sourceBuilder);
        // 执行查询
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        // 解析聚合结果
        Aggregations aggregations = searchResponse.getAggregations();
        Terms firstLetterAgg = aggregations.get("by_entry_first_letter");


        List<Map<String,Object>> list = new ArrayList<>();
        for (Bucket firstLetterBucket : firstLetterAgg.getBuckets()) {
            String firstLetter = firstLetterBucket.getKeyAsString();
            Map<String, Object> map = new HashMap<>();
            map.put("initials",firstLetter);
            Terms addressEntryAgg = firstLetterBucket.getAggregations().get("by_address_entry");
            List<Map> objects = new ArrayList<>();
            for (Bucket addressEntryBucket : addressEntryAgg.getBuckets()) {
                Map<String, Object>  objectMap= new HashMap<>();
                String addressEntry = addressEntryBucket.getKeyAsString();
                // 每个省的总数据条数
                long total = addressEntryBucket.getDocCount();
                TopHits topHitsAgg = addressEntryBucket.getAggregations().get("top_hits");
                objectMap.put("province",addressEntry);
                objectMap.put("people",total);
                // 处理 top 10 hits 数据
                List<PersonBaseInfoVO> personBaseInfo = new ArrayList<>();
                topHitsAgg.getHits().forEach(hit -> {
                    Map<String, Object> source = hit.getSourceAsMap();
                    PersonInfoEs bean = BeanUtil.toBean(source, PersonInfoEs.class);
                    PersonBaseInfoVO personBaseInfoVO = personMapper.to(bean);
                    personBaseInfoVO.setId(Long.valueOf(bean.getPersonId()));
                    personBaseInfo.add(personBaseInfoVO);
                });
                objectMap.put("list",personBaseInfo);
                objects.add(objectMap);
            }
            map.put("initialsList",objects);
            list.add(map);
        }
        return list;
    }


    /**
     *
     * @param personBaseInfoDTO
     * @return
     */
    private BoolQueryBuilder getBoolQueryBuilder(PersonBaseInfoDTO personBaseInfoDTO){
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(null != personBaseInfoDTO.getAssociationId()){
            boolQuery.must(QueryBuilders.termQuery("associationId.keyword", personBaseInfoDTO.getAssociationId().toString()));
        }
        if(null != personBaseInfoDTO.getAssociationTypeId()){
            boolQuery.must(QueryBuilders.termQuery("associationTypeId.keyword", personBaseInfoDTO.getAssociationTypeId().toString()));
        }
        if(null != personBaseInfoDTO.getPositions()){
            boolQuery.must(QueryBuilders.termQuery("positions.keyword", personBaseInfoDTO.getPositions().toString()));
        }
        if(StrUtil.isNotEmpty(personBaseInfoDTO.getYear())){
            boolQuery.must(QueryBuilders.termQuery("year.keyword", personBaseInfoDTO.getYear()));
        }
        if(StrUtil.isNotEmpty(personBaseInfoDTO.getName())){
            boolQuery.must(QueryBuilders.wildcardQuery("name.keyword",  "*" + personBaseInfoDTO.getName() + "*"));
        }
        if(StrUtil.isNotEmpty(personBaseInfoDTO.getAddressEntry())){
            boolQuery.must(QueryBuilders.termQuery("addressEntry.keyword", personBaseInfoDTO.getAddressEntry()));
        }
        if(StrUtil.isNotEmpty(personBaseInfoDTO.getAddressCity())){
            boolQuery.must(QueryBuilders.termQuery("addressCity.keyword", personBaseInfoDTO.getAddressCity()));
        }
        if(StrUtil.isNotEmpty(personBaseInfoDTO.getAddressCounty())){
            boolQuery.must(QueryBuilders.termQuery("addressCounty.keyword", personBaseInfoDTO.getAddressCounty()));
        }
        if(null != personBaseInfoDTO.getSeveral()){
            boolQuery.must(QueryBuilders.termQuery("several", personBaseInfoDTO.getSeveral()));
        }
        if(null != personBaseInfoDTO.getMassId()){
            boolQuery.must(QueryBuilders.termQuery("massId", personBaseInfoDTO.getMassId()));
        }
        if(null != personBaseInfoDTO.getDynastiesId()){
            boolQuery.must(QueryBuilders.termQuery("dynastiesId", personBaseInfoDTO.getDynastiesId()));
        }
        return boolQuery;
    }
}